package demo1.ObserverPattern;

import java.util.*;

/**
 * @ClassName ObserverPattern
 * @Description TODO
 * @Author 耀酱
 * @Date 2023/6/4 18:46
 * @Version 1.0
 */
// 观察者模式
    /*
    * 假设我们正在开发一个气象站应用程序，需要显示当前的温度、湿度和气压等信息。
    * 我们不仅想要根据新数据立即更新当前的气象数据显示，还希望在数据改变时自动更新一组气象统计数据显示。
为了实现这个功能，我们创建主题（Subject）接口和具体主题（ConcreteSubject）类来管理气象数据，
* 并向其注册和移除观察者（Observer）对象。我们同时还创建了气象数据对象（WeatherData）来存储和更新气象数据。
    * */
public class ObserverPattern {
    public static void main(String[] args) {
        // 被观察者
        WeatherStation weatherStation = new WeatherStation();
        // 观察者 可注册多个
        StatisticsDisplay statisticsDisplay = new StatisticsDisplay();
        weatherStation.registerObserver(statisticsDisplay);
        // 被观察者发送变化
        weatherStation.setMeasurements(20, 60, 1013.25f);
        weatherStation.setMeasurements(23, 70, 1012.75f);


    }
}
// 抽象主题
interface Subject {
    void registerObserver(Observer observer);
    void removeObserver(Observer observer);
    void notifyObservers();
}
// 被观察者实现类
class WeatherStation implements Subject {
    private final List<Observer> observers; // 保存已注册的观察者
    private float temperature;
    private float humidity;
    private float pressure;

    public WeatherStation() {
        observers = new ArrayList<>();
    }

    public void registerObserver(Observer observer) {
        observers.add(observer);
    }

    public void removeObserver(Observer observer) {
        observers.remove(observer);
    }

    public void notifyObservers() {
        for (Observer observer : observers) {
            observer.update(temperature, humidity, pressure);
        }
    }

    public void setMeasurements(float temperature, float humidity, float pressure) {
        this.temperature = temperature;
        this.humidity = humidity;
        this.pressure = pressure;
        measurementsChanged(); // 唤醒，通知所有已注册的观察者
    }

    public void measurementsChanged() {
        notifyObservers();
    }
}

// 定义观察者接口
interface Observer {
    // 状态变动时的操作
    void update(float temperature, float humidity, float pressure);
}

// 具体观察者类1，用于更新气象统计数据
 class StatisticsDisplay implements Observer {
    private float maxTemperature = 0.0f;
    private float minTemperature = 200.0f;
    private float temperatureSum = 0.0f;
    private int numReadings;

    public void update(float temperature, float humidity, float pressure) {
        temperatureSum += temperature;
        numReadings++;

        if (temperature > maxTemperature) {
            maxTemperature = temperature;
        }

        if (temperature < minTemperature) {
            minTemperature = temperature;
        }

        display();
    }

    public void display() {
        float avgTemperature = temperatureSum / numReadings;
        System.out.println("Avg/Max/Min Temperature = " + avgTemperature + "/" + maxTemperature + "/" + minTemperature);
    }
}